home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cvs / sprite / subr.c < prev    next >
C/C++ Source or Header  |  1991-11-03  |  9KB  |  398 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: subr.c,v 1.14.1.2 91/01/29 19:46:20 berliner Exp $";
  3. #endif !lint
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  * Various useful functions for the CVS support code.
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <sys/file.h>
  17. #include <varargs.h>
  18. #include "cvs.h"
  19.  
  20. /*
  21.  * Send a "printf" format string to stderr and die, calling the
  22.  * defined exit function first, if necessary
  23.  */
  24. error(doperror, fmt, va_alist)
  25.     int doperror;
  26.     char *fmt;
  27.     va_dcl
  28. {
  29.     extern int errno;
  30.     va_list x1;
  31.     int err = errno;
  32.  
  33.     va_start(x1);
  34.     (void) fprintf(stderr, "%s: ", progname);
  35.     (void) vfprintf(stderr, fmt, x1);
  36.     if (doperror) {
  37.     (void) fprintf(stderr, ": ");
  38.     errno = err;
  39.     perror("");
  40.     errno = 0;
  41.     } else
  42.     (void) fprintf(stderr, "\n");
  43.     va_end(x1);
  44.     Lock_Cleanup(0);
  45.     exit(1);
  46. }
  47.  
  48. /*
  49.  * Like error() above, but just display the message to stderr,
  50.  * without dying or running the exit function.
  51.  */
  52. warn(doperror, fmt, va_alist)
  53.     int doperror;
  54.     char *fmt;
  55.     va_dcl
  56. {
  57.     extern int errno;
  58.     va_list x1;
  59.     int err = errno;
  60.  
  61.     va_start(x1);
  62.     (void) fprintf(stderr, "%s: ", progname);
  63.     (void) vfprintf(stderr, fmt, x1);
  64.     if (doperror) {
  65.     (void) fprintf(stderr, ": ");
  66.     errno = err;
  67.     perror("");
  68.     errno = 0;
  69.     } else
  70.     (void) fprintf(stderr, "\n");
  71.     va_end(x1);
  72. }
  73.  
  74. /*
  75.  * Copies "from" to "to".
  76.  * mallocs a buffer large enough to hold the entire file and
  77.  * does one read/one write to do the copy.  This is reasonable,
  78.  * since source files are typically not too large.
  79.  */
  80. copy_file(from, to)
  81.     char *from;
  82.     char *to;
  83. {
  84.     struct stat sb;
  85.     int fdin, fdout;
  86.     char *buf;
  87.  
  88.     if ((fdin = open(from, O_RDONLY)) < 0)
  89.     error(1, "cannot open %s for copying", from);
  90.     if (fstat(fdin, &sb) < 0)
  91.     error(1, "cannot fstat %s", from);
  92.     if ((fdout = creat(to, (int) sb.st_mode & 07777)) < 0)
  93.     error(1, "cannot create %s for copying", to);
  94.     if (sb.st_size > 0) {
  95.     buf = xmalloc((int)sb.st_size);
  96.     if (read(fdin, buf, (int)sb.st_size) != (int)sb.st_size)
  97.         error(1, "cannot read file %s for copying", from);
  98.     if (write(fdout, buf, (int)sb.st_size) != (int)sb.st_size)
  99.         error(1, "cannot write file %s for copying", to);
  100.     free(buf);
  101.     }
  102.     (void) close(fdin);
  103.     (void) close(fdout);
  104. }
  105.  
  106. /*
  107.  * Returns non-zero if the argument file is a directory, or
  108.  * is a symbolic link which points to a directory.
  109.  */
  110. isdir(file)
  111.     char *file;
  112. {
  113.     struct stat sb;
  114.  
  115.     if (stat(file, &sb) < 0)
  116.     return (0);
  117.     return ((sb.st_mode & S_IFMT) == S_IFDIR);
  118. }
  119.  
  120. /*
  121.  * Returns non-zero if the argument file is a symbolic link.
  122.  */
  123. islink(file)
  124.     char *file;
  125. {
  126.     struct stat sb;
  127.  
  128. #ifdef S_IFLNK
  129.     if (lstat(file, &sb) < 0)
  130.     return (0);
  131.     return ((sb.st_mode & S_IFMT) == S_IFLNK);
  132. #else
  133.     return (0);
  134. #endif
  135. }
  136.  
  137. /*
  138.  * Returns non-zero if the argument file exists.
  139.  */
  140. isfile(file)
  141.     char *file;
  142. {
  143.     struct stat sb;
  144.  
  145.     if (stat(file, &sb) < 0)
  146.     return (0);
  147.     return (1);
  148. }
  149.  
  150. /*
  151.  * Returns non-zero if the argument file is readable.
  152.  * XXX - muct be careful if "cvs" is ever made setuid!
  153.  */
  154. isreadable(file)
  155.     char *file;
  156. {
  157.     return (access(file, R_OK) != -1);
  158. }
  159.  
  160. /*
  161.  * Returns non-zero if the argument file is writable
  162.  * XXX - muct be careful if "cvs" is ever made setuid!
  163.  */
  164. iswritable(file)
  165.     char *file;
  166. {
  167.     return (access(file, W_OK) != -1);
  168. }
  169.  
  170. /*
  171.  * Open a file and die if it fails
  172.  */
  173. FILE *
  174. open_file(name, mode)
  175.     char *name;
  176.     char *mode;
  177. {
  178.     FILE *fp;
  179.  
  180.     if ((fp = fopen(name, mode)) == NULL)
  181.     error(1, "cannot open %s", name);
  182.     return (fp);
  183. }
  184.  
  185. /*
  186.  * Make a directory and die if it fails
  187.  */
  188. make_directory(name)
  189.     char *name;
  190. {
  191.     if (mkdir(name, 0777) < 0)
  192.     error(1, "cannot make directory %s", name);
  193. }
  194.  
  195. /*
  196.  * malloc some data and die if it fails
  197.  */
  198. char *
  199. xmalloc(bytes)
  200.     int bytes;
  201. {
  202.     extern char *malloc();
  203.     char *cp;
  204.  
  205.     if (bytes <= 0)
  206.     error(0, "bad malloc size %d", bytes);
  207.     if ((cp = malloc((unsigned)bytes)) == NULL)
  208.     error(0, "malloc failed");
  209.     return (cp);
  210. }
  211.  
  212.  
  213. /*
  214.  * ppstrcmp() is a front-end for strcmp() when the arguments
  215.  * are pointers to pointers to chars.
  216.  */
  217. ppstrcmp(pp1, pp2)
  218.     register char **pp1, **pp2;
  219. {
  220.     return (strcmp(*pp1, *pp2));
  221. }
  222.  
  223. /*
  224.  * ppstrcmp_files() is a front-end for strcmp() when the arguments
  225.  * are pointers to pointers to chars.
  226.  * For some reason, the ppstrcmp() above sorts in reverse order when
  227.  * called from Entries2Files().
  228.  */
  229. ppstrcmp_files(pp1, pp2)
  230.     register char **pp1, **pp2;
  231. {
  232.     /*
  233.      * Reversing the arguments here cause for the
  234.      * correct alphabetical order sort, as we desire.
  235.      */
  236.     return (strcmp(*pp2, *pp1));
  237. }
  238.  
  239. /* Some UNIX distributions don't include these in their stat.h */
  240. #ifndef S_IWRITE
  241. #define    S_IWRITE    0000200        /* write permission, owner */
  242. #endif !S_IWRITE
  243. #ifndef S_IWGRP
  244. #define    S_IWGRP        0000020        /* write permission, grougroup */
  245. #endif !S_IWGRP
  246. #ifndef S_IWOTH
  247. #define    S_IWOTH        0000002        /* write permission, other */
  248. #endif !S_IWOTH
  249.  
  250. /*
  251.  * Change the mode of a file, either adding write permissions, or
  252.  * removing all write permissions.  Adding write permissions honors
  253.  * the current umask setting.
  254.  */
  255. xchmod(fname, writable)
  256.     char *fname;
  257.     int writable;
  258. {
  259.     struct stat sb;
  260.     int mode, oumask;
  261.     int        fd;
  262.     uid_t    euid;
  263.  
  264.     if (stat(fname, &sb) < 0) {
  265.     warn(1, "cannot stat %s", fname);
  266.     return;
  267.     }
  268.     euid = geteuid();
  269.     if (sb.st_uid == euid) { 
  270.     if (writable) {
  271.         oumask = umask(0);
  272.         (void) umask(oumask);
  273.         mode = sb.st_mode | ((S_IWRITE|S_IWGRP|S_IWOTH) & ~oumask);
  274.     } else {
  275.         mode = sb.st_mode & ~(S_IWRITE|S_IWGRP|S_IWOTH);
  276.     }
  277.     if (chmod(fname, mode) < 0)
  278.         warn(1, "cannot change mode of file %s", fname);
  279.     } else {
  280.     fd = open(fname, writable ? O_WRONLY : O_RDONLY);
  281.     if (fd < 0) {
  282.         warn(1, "no %s access to file %s", 
  283.         writable ? "write" : "read", fname);
  284.     } else {
  285.         close(fd);
  286.     }
  287.     }
  288. }
  289.  
  290. /*
  291.  * Rename a file and die if it fails
  292.  */
  293. rename_file(from, to)
  294.     char *from;
  295.     char *to;
  296. {
  297.     if (rename(from, to) < 0)
  298.     error(1, "cannot rename file %s to %s", from, to);
  299. }
  300.  
  301. /*
  302.  * Compare "file1" to "file2".
  303.  * Return non-zero if they don't compare exactly.
  304.  *
  305.  * mallocs a buffer large enough to hold the entire file and
  306.  * does two reads to load the buffer and calls bcmp to do the cmp.
  307.  * This is reasonable, since source files are typically not too large.
  308.  */
  309. xcmp(file1, file2)
  310.     char *file1;
  311.     char *file2;
  312. {
  313.     register char *buf1, *buf2;
  314.     struct stat sb;
  315.     off_t size;
  316.     int ret, fd1, fd2;
  317.  
  318.     if ((fd1 = open(file1, O_RDONLY)) < 0)
  319.     error(1, "cannot open file %s for comparing", file1);
  320.     if ((fd2 = open(file2, O_RDONLY)) < 0)
  321.     error(1, "cannot open file %s for comparing", file2);
  322.     if (fstat(fd1, &sb) < 0)
  323.     error(1, "cannot fstat %s", file1);
  324.     size = sb.st_size;
  325.     if (fstat(fd2, &sb) < 0)
  326.     error(1, "cannot fstat %s", file2);
  327.     if (size == sb.st_size) {
  328.     if (size == 0)
  329.         ret = 0;
  330.     else {
  331.         buf1 = xmalloc((int)size);
  332.         buf2 = xmalloc((int)size);
  333.         if (read(fd1, buf1, (int)size) != (int)size)
  334.         error(1, "cannot read file %s cor comparing", file1);
  335.         if (read(fd2, buf2, (int)size) != (int)size)
  336.         error(1, "cannot read file %s for comparing", file2);
  337.         ret = bcmp(buf1, buf2, (int)size);
  338.         free(buf1);
  339.         free(buf2);
  340.     }
  341.     } else
  342.     ret = 1;
  343.     (void) close(fd1);
  344.     (void) close(fd2);
  345.     return (ret);
  346. }
  347.  
  348. /*
  349.  * Recover the space allocated by Find_Names() and line2argv()
  350.  */
  351. free_names(pargc, argv)
  352.     int *pargc;
  353.     char *argv[];
  354. {
  355.     register int i;
  356.  
  357.     for (i = 0; i < *pargc; i++) {    /* only do through *pargc */
  358.     free(argv[i]);
  359.     }
  360.     *pargc = 0;                /* and set it to zero when done */
  361. }
  362.  
  363. /*
  364.  * Convert a line into argc/argv components and return the result in
  365.  * the arguments as passed.  Use free_names() to return the memory
  366.  * allocated here back to the free pool.
  367.  */
  368. line2argv(pargc, argv, line)
  369.     int *pargc;
  370.     char *argv[];
  371.     char *line;
  372. {
  373.     char *cp;
  374.  
  375.     *pargc = 0;
  376.     for (cp = strtok(line, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  377.     argv[*pargc] = xmalloc(strlen(cp) + 1);
  378.     (void) strcpy(argv[*pargc], cp);
  379.     (*pargc)++;
  380.     }
  381. }
  382.  
  383. /*
  384.  * Returns the number of dots ('.') found in an RCS revision number
  385.  */
  386. numdots(s)
  387.     char *s;
  388. {
  389.     char *cp;
  390.     int dots = 0;
  391.  
  392.     for (cp = s; *cp; cp++) {
  393.     if (*cp == '.')
  394.         dots++;
  395.     }
  396.     return (dots);
  397. }
  398.